#pragma once
#pragma warning (disable : 4251 )

#include <map>
#include <list>
#include <typeindex>
#include <iostream>
#include <boost/intrusive/list.hpp>
#include "Object.h"
#include "component/GameComponent.h"
#include "component/Transform.h"



namespace Boon
{
	class ProcessManager;
	class Transform;

/*!
* GameObject representing a Object which builds up its logic through attached GameComponents
* GameComponents can be attached during runtime or on startup with XML-File
* Handles GameComponents Life-Cycle-Functions ( OnCreate, OnStart, OnDestroy, OnEnable, OnDisable, Update, LateUpdate )
*/
class BOON_API GameObject : public Object
{
	#pragma region Private TypeDefs
	typedef std::map<GameObjectID, GameObjectStrong>			MapGameObjects;
	typedef std::pair<ComponentID, GameComponentStrong>			ComponentEntry; 		/*!< Custom type, entry of Compnents-type */
	typedef std::map<ComponentID, GameComponentStrong>			ComponentsMap;			/*!< Custom type to save attached components */
	typedef boost::intrusive::member_hook<GameComponent,
			boost::intrusive::list_member_hook<>,
			&Boon::GameComponent::m_GO_Member>					UpdatedComponentsOption;
	typedef boost::intrusive::list<GameComponent,
			UpdatedComponentsOption>							ListUpdatedComponents; 		/*!< Doubly linked list saving all components which will be updated once/frame */
	typedef ListUpdatedComponents								ListDirtyComponents;			/*!< Storing newly created components */
	typedef GameComponentStrong(*ComponentCreationCallback)(GameObject*);
	typedef std::map<std::string,ComponentCreationCallback>		CreationCBPerCompName;
	typedef std::list<GameComponent*>							ListNewCompDirty;

	#pragma endregion

	GameObject( const char* name );
	GameObject( const char* name, const uint_32 ComponentCount );
	GameObject( const GameObject& o );
	const GameObject& operator=( const GameObject& rhs );
	
public:
	#pragma region Static Fields
	const static uint_32						INVALID_ID = 0xFFFFFFFF;
	#pragma endregion Static Fields

	~GameObject( void );

	static GameObjectWeak						Create( const char* name );
	static GameObjectWeak						GetByID( const GameObjectID& id );


	/*! \brief		Adds a Component of type ComponentType to the GameObject
		\return		A Weak-Reference to the attached GameComponent
	*/
	template<typename ComponentType>
	Weak_ptr<ComponentType>						AddComponent();

	/*! \brief		Returns a component attached to this GameObject
					O( log(n) )
		\return		ComponentType* - The componentattached to this Gameobject
	*/
	template<typename ComponentType>
	Weak_ptr<ComponentType>						GetComponent();

	Weak_ptr<GameComponent>						GetComponent( const ComponentID id );

	/*! \brief		Returns a component attached to this GameObject looked up
					with its base type O( n )
					Note: if there are multiple objects with same base type, first
					result will be returned
		\return		ComponentType* - Attached to this GameObject
	*/
	template<typename ComponentType>
	Weak_ptr<ComponentType>						GetComponentBase();

	void										SetComponentEnabled( bool flag, GameComponent* c );

	void										SetComponentEnabled( bool flag, const ComponentID id );

	/*! \brief		Destroys the given GameObject and all of its GameComponents
	*/
	virtual void								Destroy() sealed;

	/*! \brief		Destroys a GameComponent of this GameObject identified by its componentID
		\param		ComponentID - Integer fetched by GameComponent::GetComponentID() or GameComponentDerivation::ID
	*/
	void										Destroy( const ComponentID id );

	Boon::Transform&							GetTransform();

	Boon::Renderer*								GetRenderer();

	Boon::Collider*								GetCollider();

	Boon::Rigidbody*							GetRigidbody();

	/*!
	* Nested struct providing method to register GameComponents
	* to component creation callback map
	*/
	template <typename RegisteredGameComponent>
	struct RegisterCreationCB { RegisterCreationCB( void ); };

private:

	bool										ProcessDirty();
	void										Update();
	void										LateUpdate();


	static void									RegisterComponentCreationCallback( const std::string& id, ComponentCreationCallback cb );


	ComponentsMap								m_ComponentsPerCompID; 		/*!< Structure saving all components attached to this GameObject */
	ListUpdatedComponents						m_UpdatedComponents; 		/*!< List containint all components that will be updated in update loop (can be removed with ::DisableComponent) */
	ListNewCompDirty							m_DirtyComponents;			/*!< List containing all new created components before they will put to listupdatedcomponents */
	//boost::intrusive::list_member_hook<>		m_GOManagerMember;
	Boon::Transform*							m_Transform;
	Boon::Renderer*								m_Renderer;
	Boon::Collider*								m_Collider;
	Boon::Rigidbody*							m_Rigidbody;
	GameObject*									m_Parent;


	static CreationCBPerCompName*				m_CreationCallbacks;
	static MapGameObjects						m_GameObjects; 				/*!< Map containing all GameObjects created with GameObject::Create() */
	static MapGameObjects						m_NewCreated; 				/*!< Map containint all GameObjects created during Update loop, will be put to main in ProcessManager::processUpdate()  */
	//boost::intrusive::list_member_hook<>		m_ParentMember;
	//ChildList									m_Childs; 		/*!< List containing all childs parented to this GO */
	
	//friends
	template <typename T>
	friend struct RegisterCreationCB;
	friend class ProcessManager;
};

// Must-Header-Implementation of GameObject moved to separate header file
#include "GameObject_Impl.h"

}
